package com.yl.list;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 描述: Arraylist 测试
 *
 * @author: yanglin
 * @Date: 2020-06-23-8:36
 * @Version: 1.0
 */
@Slf4j
public class ArraylistTest {

    public static void main(String[] args) {
        /**
         * 1.System.arraycopy()
         *
         * public static native void arraycopy(
         *  Object src,   //源数组
         *  int  srcPos,  //源数组的起始位置
         *  Object dest,  //目标数组
         *  int destPos,  //目标数组的起始位置
         *  int length);  //复制长度
         */
        /**
         * 1.1.深复制还是浅复制
         * 总结：System.arraycopy() 在拷贝数组的时候，采用的使用浅复制，复制结果是一维的引用变量传递给
         * 副本的一维数组，修改副本时，会影响原来的数组。
         * 浅复制
         */
        // 初始化对象数组
        User[] users = new User[]{
                new User(1, "seven", "seven@qq.com"),
                new User(2, "six", "six@qq.com"),
                new User(3, "ben", "ben@qq.com")};
        // 新建一个目标对象数组
        User[] target = new User[users.length];
        // 实现复制
        System.arraycopy(users, 0, target, 0, users.length);
        // 判断
        log.info("源对象与目标对象的物理地址是否一样：" + (users[0] == target[0] ? "浅复制" : "深复制"));
        target[0].setEmail("admin@sina.com");
        log.info("修改目标对象的属性值后源对象users：");
        for (User user : users) {
            log.info(user.toString());
        }

        /**
         * 1.2.线程安全，还是不安全
         * 总结：System.arraycopy 是线程不安全的
         */
        ArrayCopyThreadSafe threadSafe = new ArrayCopyThreadSafe();
        try {
            threadSafe.doThreadSafeCheck();
        } catch (Exception e) {
            e.printStackTrace();
        }

        /**
         * 1.3.高效还是低效
         * 总结：当测试数组的范围比较小的时候，两者相差的时间无几，当测试数组的长度达到百万级别，
         * System.arraycopy的速度优势就开始体现了，根据对底层的理解，System.arraycopy是对内存
         * 直接进行复制，减少了for循环过程中的寻址时间，从而提高了效能。
         */
        String[] srcArray = new String[1000000];
        String[] forArray = new String[srcArray.length];
        String[] arrayCopyArray  = new String[srcArray.length];

        //初始化数组
        for(int index  = 0 ; index  < srcArray.length ; index ++){
            srcArray[index] = String.valueOf(index);
        }

        long forStartTime = System.currentTimeMillis();
        for(int index  = 0 ; index  < srcArray.length ; index ++){
            forArray[index] = srcArray[index];
        }
        long forEndTime = System.currentTimeMillis();
        log.info("for方式复制数组耗时(单位毫秒)："  + (forEndTime - forStartTime));

        long arrayCopyStartTime = System.currentTimeMillis();
        System.arraycopy(srcArray,0,arrayCopyArray,0,srcArray.length);
        long arrayCopyEndTime = System.currentTimeMillis();
        log.info("System.arraycopy复制数组耗时(单位毫秒)："  + (arrayCopyEndTime - arrayCopyStartTime));


        /**
         * 2.subList(int fromIndex, int toIndex) 方法
         * 如果对原 list 调用 subList(int fromIndex, int toIndex) 方法：
         * 1.原 list 可以进行修改与查询操作，但是修改后 subList 中对应的元素值也会对应改变（index 不超过 subList 的大小），如果对原 list
         * 执行删除与添加时会报 ConcurrentModificationException 并发修改异常
         * 2.如果对 subList 执行增删改操作会对原 list 执行同样的操作
         */
        List<String> stringList = new ArrayList<>();
        for (int i = 0; i < 10; i ++){
            stringList.add("sub-"+i);
        }
        // subList
        List<String> stringSub = stringList.subList(5, 9);
        // 修改
        stringSub.set(0, "sun_update01");
        log.info(stringList.get(5)+"              "+stringSub.get(0));
        // 新增
        try{
            stringList.add("add");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            stringSub.add("sun_add01");
            stringSub.forEach(str -> {
                log.info(str);
            });
        }

        /**
         * 3.ArrayList 扩容机制 1.5倍
         */

    }

    static class User {
        private Integer id;
        private String username;
        private String email;

        // 无参构造函数
        public User() {
        }

        // 有参的构造函数
        public User(Integer id, String username, String email) {
            super();
            this.id = id;
            this.username = username;
            this.email = email;
        }

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getEmail() {
            return email;
        }

        public void setEmail(String email) {
            this.email = email;
        }

        @Override
        public String toString() {
            return "User [id=" + id + ", username=" + username + ", email=" + email + "]";
        }
    }

    static class ArrayCopyThreadSafe {
        private  int[] arrayOriginal = new int[1024 * 1024 * 10];
        private  int[] arraySrc = new int[1024 * 1024 * 10];
        private  int[] arrayDist = new int[1024 * 1024 * 10];
        private ReentrantLock lock = new ReentrantLock();

        private void modify() {
            for (int i = 0; i < arraySrc.length; i++) {
                arraySrc[i] = i + 1;
            }
        }

        private void copy() {
            System.arraycopy(arraySrc, 0, arrayDist, 0, arraySrc.length);
        }

        private void init() {
            for (int i = 0; i < arraySrc.length; i++) {
                arrayOriginal[i] = i;
                arraySrc[i] = i;
                arrayDist[i] = 0;
            }
        }

        private void doThreadSafeCheck() throws Exception {
            for (int i = 0; i < 100; i++) {
                log.info("run count: " + (i + 1));
                init();
                Condition condition = lock.newCondition();

                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        lock.lock();
                        try{
                            condition.signalAll();
                        }catch (Exception e){

                        }finally {
                            lock.unlock();
                            copy();
                        }
                    }
                }).start();

                lock.lock();
                try{
                    // 这里使用 Condition 来保证拷贝线程先已经运行了.
                    condition.await();
                }catch (Exception e){

                }finally {
                    lock.unlock();
                }

                Thread.sleep(2); // 休眠2毫秒, 确保拷贝操作已经执行了, 才执行修改操作.
                modify();

                // System.arraycopy 是线程不安全的, 那么 arrayOriginal 不等于 arrayDist.
                if (!Arrays.equals(arrayOriginal, arrayDist)) {
                    throw new RuntimeException("System.arraycopy is not thread safe");
                }
            }
        }

    }

}